package org.robotlegs.mvcs
{
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.system.ApplicationDomain;
	
	import org.robotlegs.adapters.SwiftSuspendersInjector;
	import org.robotlegs.adapters.SwiftSuspendersReflector;
	import org.robotlegs.base.CommandMap;
	import org.robotlegs.base.ContextBase;
	import org.robotlegs.base.ContextError;
	import org.robotlegs.base.ContextEvent;
	import org.robotlegs.base.EventMap;
	import org.robotlegs.base.MediatorMap;
	import org.robotlegs.base.ViewMap;
	import org.robotlegs.core.ICommandMap;
	import org.robotlegs.core.IContext;
	import org.robotlegs.core.IEventMap;
	import org.robotlegs.core.IInjector;
	import org.robotlegs.core.IMediatorMap;
	import org.robotlegs.core.IReflector;
	import org.robotlegs.core.IViewMap;

	
	[Event(name="startupComplete", type="org.robotlegs.base.ContextEvent")]
	
	

	/**
	 * Model 仅【可通知】
	 * View 完全隔离...
	 * Mediator 注入 View，【可通知】与【被通知】，一般属于监听角色。
	 * Command 注入 Model & Service & Event，在对框架事件的处理中被触发. 一个事件既可以被一个 Mediator 接收, 也可以触发一个 command.
	 * Service 注入 Model，仅【可通知】，执行建议在Command中调用，而不是在Mediator中
	 * 
	 * 不建议在一个 Command 里直接和 Mediator 交互.
	 * 虽然这是可行的, 但会将这个 Mediator 耦合到这个 Command. 
	 * 因为 Mediator 不像 Service 和 Model, 它可以接受系统事件, 
	 * 更好的做法是让 Command 广播事件, 然后让需要响应这些事件的 Mediator 监听它们.
	 */
public class Context extends ContextBase implements IContext
{
	public function Context(contextView:DisplayObjectContainer = null, autoStartup:Boolean = true)
	{
		super();
		
		_contextView = contextView;
		_autoStartup = autoStartup;
		
		if (_contextView)
		{
			mapInjections();
			checkAutoStartup();
		}
	}
	
	
	
	
	protected var _injector:IInjector;

	protected var _reflector:IReflector;

	protected var _autoStartup:Boolean;

	protected var _contextView:DisplayObjectContainer;

	protected var _commandMap:ICommandMap;

	protected var _mediatorMap:IMediatorMap;

	protected var _viewMap:IViewMap;

	
	
	
	
	public function startup():void
	{
		dispatchEvent(new ContextEvent(ContextEvent.STARTUP_COMPLETE));
	}
	

	public function shutdown():void
	{
		dispatchEvent(new ContextEvent(ContextEvent.SHUTDOWN_COMPLETE));
	}
	

	public function get contextView():DisplayObjectContainer{return _contextView;}
	public function set contextView(value:DisplayObjectContainer):void
	{
		if (value == _contextView)
			return;
		
		if (_contextView)
			throw new ContextError(ContextError.E_CONTEXT_VIEW_OVR);
		
		_contextView = value;
		mapInjections();
		checkAutoStartup();
	}
	

	protected function get injector():IInjector{return _injector ||= createInjector();}
	protected function set injector(value:IInjector):void{_injector = value;}

	
	protected function get reflector():IReflector{return _reflector ||= new SwiftSuspendersReflector();}
	protected function set reflector(value:IReflector):void{_reflector = value;}
	

	protected function get commandMap():ICommandMap{return _commandMap ||= new CommandMap(eventDispatcher, createChildInjector(), reflector);}
	protected function set commandMap(value:ICommandMap):void{_commandMap = value;}
	

	protected function get mediatorMap():IMediatorMap{return _mediatorMap ||= new MediatorMap(contextView, createChildInjector(), reflector);}
	protected function set mediatorMap(value:IMediatorMap):void{_mediatorMap = value;}
	

	protected function get viewMap():IViewMap{return _viewMap ||= new ViewMap(contextView, injector);}
	protected function set viewMap(value:IViewMap):void{_viewMap = value;}

	
	protected function mapInjections():void
	{
		injector.mapValue(IReflector, reflector);
		injector.mapValue(IInjector, injector);
		injector.mapValue(IEventDispatcher, eventDispatcher);
		injector.mapValue(DisplayObjectContainer, contextView);
		injector.mapValue(ICommandMap, commandMap);
		injector.mapValue(IMediatorMap, mediatorMap);
		injector.mapValue(IViewMap, viewMap);
		injector.mapClass(IEventMap, EventMap);
	}

	
	
	
	protected function checkAutoStartup():void
	{
		if (_autoStartup && contextView)
		{
			contextView.stage ? startup() : contextView.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
		}
	}

	
	protected function onAddedToStage(e:Event):void
	{
		contextView.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
		startup();
	}
	

	protected function createInjector():IInjector
	{
		var injector:IInjector = new SwiftSuspendersInjector();
		injector.applicationDomain = getApplicationDomainFromContextView();
		return injector;
	}
	

	protected function createChildInjector():IInjector
	{
		return injector.createChild(getApplicationDomainFromContextView());
	}
	

	protected function getApplicationDomainFromContextView():ApplicationDomain
	{
		if (contextView && contextView.loaderInfo)
			return contextView.loaderInfo.applicationDomain;
		return ApplicationDomain.currentDomain;
	}

}
}